<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/12/4
 * Time: 14:56
 */

namespace common\business\empdept;

use common\consts\CommonResources;
use common\consts\Consts;
use common\helpers\StringUtil;
use common\models\Department;
use common\models\EmployeeDepartment;
use common\models\kingdee\OrgAdmin;
use common\models\kingdee\PersonPosition;
use Yii;
use common\models\Employee;
use common\result\ActionResult;
use yii\db\Query;

class EmployeeDepartmentService
{
    protected $_rootOrgNumber = 'STEC';

    /**
     * @var string
     */
    protected $_departmentNumber;
    public function setDepartmentNumber($departmentId){
        $this->_departmentNumber = $departmentId;
    }

    /**
     * @var int
     */
    protected $_totalCount = 0;


    /**
     * @param $result ActionResult
     * @param callback|null $writeBackHandler
     * @return ActionResult
     */
    protected function stop($result, $writeBackHandler = null){
        if ($writeBackHandler){
            $paramArr = [
                'totalCount' => $result->total_count,
                'finishCount' => $result->total_count,
                'message' => $result->message,
            ];
            call_user_func_array($writeBackHandler, $paramArr);
        }
        return $result;
    }

    /**
     * @param callback|null $writeBackHandler
     * @param string $parentDepartmentNumber
     * @param ActionResult $currentResult
     * @param integer $currentCount
     * @return ActionResult
     */
    public function sync($writeBackHandler = null, $parentDepartmentNumber = null, $currentResult = null, $currentCount = 0){
        $action = Yii::t('app', 'Sync');
        $modelClass = Yii::t('app', 'Employee Department Relation');

        $db = PersonPosition::getDb();

        $this->_departmentNumber = $parentDepartmentNumber;

        $totalResult = $currentResult;
        if (!$totalResult){
            $totalResult = new ActionResult();
        }

        if (StringUtil::isNullOrWhiteSpace($this->_departmentNumber)){
            $this->_departmentNumber = $this->_rootOrgNumber;
        }
        $orgInDb = OrgAdmin::findOne([
            'FNUMBER' => $this->_departmentNumber,
        ]);
        if (!$orgInDb){
            $totalResult = new ActionResult(false, CommonResources::ACTION_NAME_MODEL_FAIL_WITH_REASON($action, $modelClass, $this->_departmentNumber, 'Org Not Found'));
            return $this->stop($totalResult);
        }
        $childOrgs = OrgAdmin::findAll([
            'FPARENTID' => $orgInDb->FID,
        ]);
        foreach ($childOrgs as $childOrg){
            $query = (new Query())->from('T_HR_PERSONPOSITION THRPP')
                ->leftJoin('T_BD_PERSON TBP', 'TBP.FID = THRPP.FPERSONID')
                ->leftJoin('T_ORG_ADMIN TOA', 'TOA.FID = THRPP.FPERSONDEP')
                ->select([
                    'employee_name' => 'TBP.FNAME_L2',
                    'employee_number' => 'TBP.FNUMBER',
                    'department_name' => 'TOA.FNAME_L2',
                    'department_number' => 'TOA.FNUMBER',
                    'department_display_name' => 'TOA.FDISPLAYNAME_L2',
                ])->andFilterWhere([
                    'TOA.FNUMBER' => $childOrg->FNUMBER,
                ])->orderBy([
                    'TBP.FID' => SORT_ASC,
                ]);

            foreach ($query->all($db) as $childItem){
                $this->createOrUpdateHierachy($childOrg, $childItem['employee_name'], $childItem['employee_number'], $totalResult, 0);
            }
            $this->sync($writeBackHandler, $childOrg->FNUMBER, $totalResult, $this->_totalCount);
        }

        $query = (new Query())->from('T_HR_PERSONPOSITION THRPP')
            ->leftJoin('T_BD_PERSON TBP', 'TBP.FID = THRPP.FPERSONID')
            ->leftJoin('T_ORG_ADMIN TOA', 'TOA.FID = THRPP.FPERSONDEP')
            ->select([
                'employee_name' => 'TBP.FNAME_L2',
                'employee_number' => 'TBP.FNUMBER',
                'department_name' => 'TOA.FNAME_L2',
                'department_number' => 'TOA.FNUMBER',
                'department_display_name' => 'TOA.FDISPLAYNAME_L2',
            ]);
        if(!StringUtil::isNullOrWhiteSpace($this->_departmentNumber)){
            $query->andFilterWhere([
                'TOA.FNUMBER' => $this->_departmentNumber,
            ]);
        }
        $query->orderBy([
            'TBP.FID' => SORT_ASC,
        ]);

        $this->_totalCount = $currentCount + $query->count('*', $db);

        $offset = 0;
        $pageSize = 100;
        $count = $pageSize;

        while ($count >= $pageSize) {
            $all = $query->offset($offset)->limit($pageSize)->all($db);
            $count = count($all);
            $offset += $pageSize;
            foreach ($all as $item){
                $newEmployeeDepartment = new EmployeeDepartment();
                $newEmployeeDepartment->setAttributes($item);
                $newEmployeeDepartment->hr_status = Consts::SYNC_STATUS_FINISHED;
                $newEmployeeDepartment->qywx_status = Consts::SYNC_STATUS_NEW;

                $this->createOrUpdateEmployeeDepartment(
                    $newEmployeeDepartment->employee_name,
                    $newEmployeeDepartment->employee_number,
                    $newEmployeeDepartment->department_name,
                    $newEmployeeDepartment->department_number,
                    $newEmployeeDepartment->department_display_name,
                    $totalResult
                );

                if ($writeBackHandler){
                    $paramArr = [
                        'totalCount' => $totalResult->total_count,
                        'finishCount' => $totalResult->total_count,
                        'message' => $totalResult->message,
                    ];
                    call_user_func_array($writeBackHandler, $paramArr);
                }
            }
        }
        return $totalResult;
    }

    /**
     * @param $org OrgAdmin
     * @param string $employeeName
     * @param string $employeeNumber
     * @param int $level
     * @param $totalResult ActionResult
     */
    protected function createOrUpdateHierachy($org, $employeeName, $employeeNumber, $totalResult, $level = 0){
        $this->createOrUpdateEmployeeDepartment($employeeName, $employeeNumber, $org->FNAME_L2, $org->FNUMBER, $org->FDISPLAYNAME_L2, $totalResult, $level);
        $parentOrg = OrgAdmin::findOne([
            'FID' => $org->FPARENTID,
        ]);
        if ($parentOrg){
            $newLevel = $level +1;
            $this->createOrUpdateHierachy($parentOrg, $employeeName, $employeeNumber, $totalResult, $newLevel);
        }
    }

    /**
     * @param $employee_name string
     * @param $employee_number string
     * @param $department_name string
     * @param $department_number string
     * @param $department_display_name string
     * @param int $level
     * @param $totalResult ActionResult
     */
    protected function createOrUpdateEmployeeDepartment($employee_name, $employee_number, $department_name, $department_number, $department_display_name, $totalResult, $level = 0){
        $newEmployeeDepartment = new EmployeeDepartment([
            'employee_name' => $employee_name,
            'employee_number' => $employee_number,
            'department_name' => $department_name,
            'department_number' => $department_number,
            'department_display_name' => $department_display_name,
            'hr_status' =>  Consts::SYNC_STATUS_FINISHED,
            'qywx_status' => Consts::SYNC_STATUS_NEW,
            'level' => $level,
        ]);

        EmployeeDepartment::deleteAll('employee_number=:employee_number and level=:level and department_number<>:department_number',
            [
                ':employee_number' => $employee_number,
                ':level' => $level,
                ':department_number' => $department_number,
            ]
        );

        $employeeDepartmentInDb = EmployeeDepartment::findOne([
            'employee_number' => $employee_number,
            'department_number' => $department_number,
        ]);

        $api = new EmployeeDepartmentApiHandler();
        if (!$employeeDepartmentInDb){
            $totalResult->addSubResult($api->createEmployeeDepartment($newEmployeeDepartment));
        }
        else {
            $totalResult->addSubResult($api->updateEmployeeDepartment($newEmployeeDepartment, $employeeDepartmentInDb));
        }
    }
}